﻿var olMap = window.olMap = olMap || {
    version: 1.0,
    author: 'legendofkage',
    serviceProxyUrl: 'MapProxy.ashx',
    /**
     * 在dom文档加载完成后，ready的回调函数则会被调用，类似jquery的ready
     */
    ready: function(fn) {
        if (document.addEventListener) {
            //标准浏览器  
            document.addEventListener('DOMContentLoaded', function() {
                //注销事件,避免反复触发  
                document.removeEventListener('DOMContentLoaded', arguments.callee, false);
                fn();
            }, false);
        } else if (document.attachEvent) {
            //IE浏览器  
            document.attachEvent('onreadystatechange', function() {
                if (document.readyState == 'complete') {
                    document.detachEvent('onreadystatechange', arguments.callee);
                    fn();
                }
            });
        }
    },
    /**
     * 实现继承,subClass继承parentClass
     */
    inherits: function(subClass, parentClass) {
        var obj = Object.create(parentClass.prototype);
        subClass.prototype = obj;
        subClass.prototype.constructor = subClass;
        subClass.__super__ = parentClass.prototype;
    }
};

/**
 * 地图类（可以多次创建不同的地图），如果是个单例，则调用olMap.Map.getInstance
 */
olMap.Map = (function() {

    var opt_settings = {
        el: '', //地图html容器
        projection: ol.proj.get("EPSG:3857"),
        origin: [0, 0],
        resolutions: [],
        extent: ol.proj.get("EPSG:3857").getExtent(),
        zoom: 0,
        tileUrl: '', //离线瓦片url
        mapType: 'bdMap',
        logo: false
    };
    for (var i = 0; i < 19; i++) {
        opt_settings.resolutions[i] = Math.pow(2, 18 - i);
    }

    //将10进制转16进制，余位补0，凑成ArcServer的切片格式
    function padLeft(val, num, radix) {
        var str = val.toString(radix || 10);
        return (new Array(num).join('0') + str).slice(-num);
    }

    var layerFactory = {
        'bdMap': function(opt) {
            return new ol.layer.Tile({
                source: new ol.source.TileImage({
                    projection: opt.projection,
                    tileGrid: new ol.tilegrid.TileGrid({
                        origin: [0, 0],
                        resolutions: opt.resolutions
                    }),
                    tileUrlFunction: function(tileCoord, pixelRatio, proj) {
                        if (!tileCoord) {
                            return "";
                        }
                        var z = tileCoord[0];
                        var x = tileCoord[1];
                        var y = tileCoord[2];

                        if (x < 0) {
                            x = "M" + (-x);
                        }
                        if (y < 0) {
                            y = "M" + (-y);
                        }
                        return "http://online3.map.bdimg.com/onlinelabel/?qt=tile&x=" + x + "&y=" + y + "&z=" + z + "&styles=pl&udt=20170516&scaler=1&p=1";
                    }
                })
            });
        },
        'offline': function(opt) {
            return new ol.layer.Tile({
                source: new ol.source.XYZ({
                    projection: opt.projection,
                    tileGrid: new ol.tilegrid.TileGrid({
                        origin: opt.origin,
                        extent: opt.extent,
                        resolutions: opt.resolutions
                    }),
                    tileUrlFunction: function(tileCoord) {
                        var x = 'C' + padLeft(tileCoord[1], 8, 16);
                        var y = 'R' + padLeft(-tileCoord[2] - 1, 8, 16);
                        var z = 'L' + padLeft(tileCoord[0], 2, 10);
                        return opt.tileUrl + z + '/' + y + '/' + x + '.png';
                    }
                })
            });
        }
    };

    function layer(opt) {
        var _opt = Object.assign({}, opt_settings);
        opt = Object.assign(_opt, opt);
        opt.projection.setExtent(opt.extent);

        var map = new ol.Map({
            layers: [
                layerFactory[opt.mapType](opt)
            ],
            target: opt.el,
            logo: opt.logo,
            view: new ol.View({
                projection: opt.projection,
                extent: opt.extent,
                resolutions: opt.resolutions,
                center: opt.center || ol.extent.getCenter(opt.extent),
                zoom: opt.zoom
            })
        });
        return map;
    }
    return layer;
})();

/**
 * 创建单例地图
 */
olMap.Map.getInstance = (function() {
    var instance;
    return function(opt) {
        !instance && (instance = new olMap.Map(opt));
        return instance;
    }
})();

/**
 * 自定义投影坐标系以及坐标间的转换
 */
olMap.projection = (function() {
    var srsSource = {
        "EPSG:3857": ol.proj.get("EPSG:3857"),
        "EPSG:4326": ol.proj.get("EPSG:4326")
    };
    return {
        defs: function(srs, conversion) {
            if (!srsSource.hasOwnProperty(srs)) {
                proj4.defs(srs, conversion);
                srsSource[srs] = ol.proj.get(srs);
            }
            return srsSource[srs];
        },
        get: function(srs) {
            return srsSource[srs];
        }
    }
})()

/**
 * 地图服务，封装wms跟wfs.
 */
olMap.service = (function() {

    var instance = {},
        cache = {};

    function service(url) {
        this.url = url;
    }
    service.prototype.getUrl = function(url) {
        this.url = url;
    }
    service.prototype.request = function(opt, workspace) {
        var _opt = Object.assign({}, this.getDefaultOpt());
        var regExp = new RegExp('/geoserver/\\w+/(wms|oms)$', 'i'),
            svcUrl = this.url;
        var ws = workspace || cache['wmsWorkspace'];
        if (!regExp.test(this.url)) {
            if (!ws) {
                throw new Error("请提供workspace参数值,即地图服务的工作区");
            } else {
                svcUrl += '/' + ws + "/wms?";
                workspace && (cache['wmsWorkspace'] = workspace);
            }
        } else {
            if (ws) {
                regExp = new RegExp('\\w+(?=/(wms|oms))', 'i');
                svcUrl = this.url.replace(regExp, ws);
            } else
                svcUrl = this.url;
        }
        var content = new RegExp('\\w+(?=/(wms|oms))', 'i').exec(svcUrl);
        var layers = [];
        if (typeof opt === 'string') {
            layers = opt.split(',');
        } else {
            _opt = Object.assign(_opt, opt);
            layers = _opt.split(',');
        }
        layers = layers.map(function(item, index) {
            if (item.indexOf(":") == -1) {
                return content[0] + ":" + item;
            } else
                return item;
        });
        _opt.LAYERS = layers.join();
        if (svcUrl.substr(svcUrl.length - 1) != "?")
            svcUrl += "?";
        return this.initLayer(_opt, svcUrl);
    }

    service.prototype.getDefaultOpt = function() {
        throw new TypeError("请在子类中实现该方法!");
    }

    service.prototype.initLayer = function() {
        throw new TypeError("请在子类中实现该方法!");
    }

    function wms() {
        wms.__super__ && wms.__super__.constructor.apply(this, arguments);
    }
    olMap.inherits(wms, service);

    wms.getDefaultOpt = function() {
        return {
            FORMAT: 'image/png',
            VERSION: '1.1.0',
            tiled: true,
            STYLES: '',
            LAYERS: ''
        }
    }

    wms.prototype.initLayer = function(opt, url) {
        var layer = new ol.layer.Tile({
            source: new ol.source.TileWMS({
                url: olMap.serviceProxyUrl + "?url=" + url,
                params: opt
            })
        });
        return layer;
    }

    wms.getInstance = function(url) {
        !instance.wms && (instance.wms = new wms(url));
        return instance.wms;
    }


    function wfs() {
        wfs.__super__ && wfs.__super__.constructor.apply(this, arguments);
    }
    olMap.inherits(wfs, service);

    wfs.getDefaultOpt = function() {
        return {
            srid: '',
            service: 'WFS',
            request: 'GetFeature',
            version: '1.1.0',
            outputFormat: 'application/json',
            propertyName: '*',
            typeName: undefined,
            filter: undefined,
            cql_filter: undefined,
            maxFeatures: 50 //查询最大数量，不设置时默认为全部
        }
    }

    wfs.prototype.initLayer = function(opt, url, callback) {
        if (!opt.typeName) {
            throw new Error("wfs请求typeName[图层]是必须的");
        } else if (opt.bbox) {
            if (Array.isArray(opt.bbox)) {
                opt.bbox.push(opt.srid);
                opt.bbox = opt.bbox.join();
            }
        }
        $.ajax(olMap.serviceProxyUrl + "?url=" + url, {
            type: 'GET',
            data: opt,
            dataType: 'json',
            success: function(result) {
                if (result) {
                    var format = new ol.format.GeoJSON({});
                    var featureData = format.readFeatures(result);
                    typeof callback == "function" && callback(featureData);
                }
            },
            error: function(result) {
                console.log(result);
            }
        });
    }

    wfs.getInstance = function(url) {
        !instance.wfs && (instance.wfs = new wfs(url));
        return instance.wfs;
    }

    return {
        wms: wms,
        wfs: wfs
    }
})();